package com.sky.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.sky.constant.MessageConstant;
import com.sky.dto.UserLoginDTO;
import com.sky.entity.User;
import com.sky.exception.LoginFailedException;
import com.sky.mapper.UserMapper;
import com.sky.properties.WeChatProperties;
import com.sky.service.UserService;
import com.sky.utils.HttpClientUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

/**
 *  controller层主要就是来调用service层
 *  service层是用来处理处理具体的逻辑的; 具体该怎么实现,然后调用mapper层对数据库操作
 *  下面就是具体分析各个功能的逻辑,首先要干什么,怎么获取;业务的逻辑结构
 * @author DragonflyYue
 */
@Service
@Slf4j
public class UserServiceImpl implements UserService {

    //微信服务接口地址,,下面定义成了一个常量
    public static final String WX_LOGIN = "https://api.weixin.qq.com/sns/jscode2session";

    @Autowired
    private WeChatProperties weChatProperties;

    @Autowired
    private UserMapper userMapper;

    /**
     * 微信登录
     * 这个微信登录和传统的账号密码登陆不同
     * @param userLoginDTO
     * @return
     */
    @Override
    public User wxLogin(UserLoginDTO userLoginDTO) {

        //调用微信接口服务,获得当前微信用户的openId,唯一标识微信用户的
            //https://api.weixin.qq.com/sns/jscode2session
            //通过httpclient来发送请求,就能访问上面的地址

        //Map<String, String> map = new HashMap<>();
        ////传入具体的请求参数,,查看对应的接口文档
        //map.put("appid",weChatProperties.getAppid());  //在yml中配置了appid的值,所以可以通过配置属性类直接获取
        //map.put("secret",weChatProperties.getSecret());
        //map.put("js_code",userLoginDTO.getCode());   //这个授权码code是,通过UserLoginDTO传进来的
        //map.put("grant_type","authorization_code");   //这个值是固定的,微信服务的文档就让默认用这个值
        //String json =  HttpClientUtil.doGet(WX_LOGIN,map);   //这里就把这个get方式的请求发出去了
        //    //在微信服务对应的文档中,这个请求返回的是一个json数据包的对象,这里用String接收
        //    //下面我们就要把这个字符串类型的json解析,把里面的openId解析出来
        //JSONObject jsonObject = JSON.parseObject(json);
        //String openid = jsonObject.getString("openid");   //解析出对应的openid

        //对上面的代码,抽离成了一个方法,因为代码比较独立,不会影响到整体逻辑
            //这个getOpenid方法在当前类,最下面定义的,,也可以对比着上面注释的代码来看,基本一模一样
        String openid = getOpenid(userLoginDTO.getCode());

        //判断openId是否为null,,如果为空表示登录失败,抛出业务异常
        if (openid == null){
            throw new LoginFailedException(MessageConstant.LOGIN_FAILED);  //通过常量的方式传入对应的异常信息
        }

        //判断当前用户是否为新用户-----------即看openId是否在我们数据库中有存储
            //去数据库中查user表中这个字段
        User user = userMapper.getByOpenid(openid);

        //如果是新用户,自动完成注册
        if (user == null){
            //数据库中没有存储相关数据,,所以此时说明是新用户
            //构造User对象
            user = User.builder()
                    .openid(openid)
                    .createTime(LocalDateTime.now())
                    .build();        //其余的信息暂时还没获取到,所以就没设置;后面可以通过个人中心来完善相关信息
            //这里把新用户的数据,插入到数据库中
            userMapper.insert(user);

        }
        //返回这个用户对象
        return user;
            //也可以看出这里service层和前面controller层的区别,这里就返回的是user;
            //而controller层返回的是  Result.success(userLoginVo)
    }

    /**
     * 调用微信接口服务,获得当前微信用户的openId
     * 这个方法只是把上面独立的功能抽出来的一个方法,,所以也只在当前类会用到
     * 因为下面功能都比较独立,所以可以单独拿出来写个方法
     * @return
     */
    private String getOpenid(String code){      //这里的形参传入的是微信小程序的授权码
        //感觉这个形参随便写一个就行,,对照上面49行原来的代码理解就明白了,,
            // 传入appid也可以呀,上面用weChatProperties.getAppid获取到的appid当做实参传递就行了;
            //或者说,,这个方法完全可以写成一个无参的方法;
                // 还是用code好,因为UserLoginDTO里面本身就一个code属性,所以请求的参数就是code,这才符合逻辑,
                // 自己上面那种想法只是说方法代码没错,但是没法复用,无法和整个业务结构关联起来

        //调用微信接口服务,获得当前微信用户的openId,唯一标识微信用户的
            //https://api.weixin.qq.com/sns/jscode2session
        //通过httpclient来发送请求,就能访问上面的地址
        Map<String, String> map = new HashMap<>();
        //传入具体的请求参数,,查看对应的接口文档
        map.put("appid",weChatProperties.getAppid());  //在yml中配置了appid的值,所以可以通过配置属性类直接获取
        map.put("secret",weChatProperties.getSecret());
        map.put("js_code",code);   //这个授权码code是,通过UserLoginDTO传进来的
        map.put("grant_type","authorization_code");   //这个值是固定的,微信服务的文档就让默认用这个值
        String json =  HttpClientUtil.doGet(WX_LOGIN,map);   //这里就把这个get方式的请求发出去了
        //在微信服务对应的文档中,这个请求返回的是一个json数据包的对象,这里用String接收
        //下面我们就要把这个字符串类型的json解析,把里面的openId解析出来
        JSONObject jsonObject = JSON.parseObject(json);
        String openid = jsonObject.getString("openid");   //解析出对应的openid

        return openid;
    }
}
